### FUNCOES ###

# Funcao que da a probabilidade dada uma tabela, uma classe e uma frase

getProbability = function(tabela, classe, frase, fator = 1){
  
  tamanhoTotal = length(tabela)/2;
  
  countFrase = 0;
  countTotal = 0;
  tabela_classe = tabela[[classe]];
  
  if(!is.null(tabela_classe)){
    countTotal = tabela_classe$total;
    tabela_count = tabela[[classe]]$contador[[frase]];
    if(!is.null(tabela_count)){
      countFrase = tabela_count;
    }
  }
  
  prob = (1 + countFrase) / (countTotal + tamanhoTotal);
  
  return(prob);
}

getProbabilityHax = function(tabela, classe, frase, fator = 1){
  
  tamanhoTotal = length(tabela)/2;
  
  countFrase = 0;
  countTotal = 0;
  tabela_classe = tabela[[classe]];
  
  if(!is.null(tabela_classe)){
    countTotal = tabela_classe$total;
    tabela_count = tabela[[classe]]$contador[[frase]];
    if(!is.null(tabela_count)){
      countFrase = tabela_count;
    }
  }
  
  prob = (countFrase) / (countTotal + tamanhoTotal);
  
  return(prob);
}

# Funcao que classifica um texto

classify = function(text, dictionary, bigramTable, trigramTable, quadgramTable){
  
  text = tolower(x=text);
  class = c('','','');
  prob = c(0,0,0);
  totalDict = sum(dictionary) + length(dictionary);
  
  # Usa a formula do naive bayes:
  # p(c|frase) = p(c) * p(bigrama|c) * p(trigrama|c) * p(quadgrama|c)
  # Ajustada para evitar multiplicacoes por 0.
  
  textSplitted = unlist(strsplit(text, split=" "));
  
  textBi = textSplitted[3];
  textTri = paste(textSplitted[2], textSplitted[3]);
  textQuad = paste(textSplitted[1], textSplitted[2], textSplitted[3]);
  for(i in row.names(dictionary)){
    
    #print(i)
    #print(textBi)
    probBi = getProbability(tabela = bigramTable, classe = i, frase = textBi);
    probTri = getProbability(tabela = trigramTable, classe = i, frase = textTri);
    probQuad = getProbability(tabela = quadgramTable, classe = i, frase = textQuad);
    
    prob_temp = (1 + dictionary[i,1])/totalDict * probBi * probTri * probQuad;
    #prob_temp = probTri * probQuad;
    class_temp = i;
    
    if(prob_temp > prob[[1]]){
      swap_class = class[[1]];
      swap_prob = prob[[1]];
      
      class[[1]] = class_temp;
      prob[[1]] = prob_temp;
      
      class_temp = swap_class;
      prob_temp = swap_prob;
    }
    
    if(prob_temp > prob[[2]]){
      swap_class = class[[2]];
      swap_prob = prob[[2]];
      
      class[[2]] = class_temp;
      prob[[2]] = prob_temp;
      
      class_temp = swap_class;
      prob_temp = swap_prob;
    }
    
    if(prob_temp > prob[[3]]){
      swap_class = class[[3]];
      swap_prob = prob[[3]];
      
      class[[3]] = class_temp;
      prob[[3]] = prob_temp;
      
      class_temp = swap_class;
      prob_temp = swap_prob;
    }
    
  }
  
  return (list(class,prob));
}

classifyHax = function(text, dictionary, bigramTable, trigramTable, quadgramTable){
  
  text = tolower(x=text);
  class = c('','','','');
  prob = c(0,0,0,0);
  totalDict = sum(dictionary) + length(dictionary);
  
  # Usa a formula do naive bayes:
  # p(c|frase) = p(c) * p(bigrama|c) * p(trigrama|c) * p(quadgrama|c)
  # Ajustada para evitar multiplicacoes por 0.
  
  textSplitted = unlist(strsplit(text, split=" "));
  
  textBi = textSplitted[3];
  textTri = paste(textSplitted[2], textSplitted[3]);
  textQuad = paste(textSplitted[1], textSplitted[2], textSplitted[3]);
  
  pesosDicionario = dictionary/sum(dictionary);
  for(i in row.names(dictionary)){
    
    #print(i)
    #print(textBi)
    probQuad = getProbabilityHax(tabela = quadgramTable, classe = i, frase = textQuad);
    if(probQuad > prob[1]){
      prob[1] = probQuad;
      class[1] = i;
      
    }
    
    else{
      probTri = getProbabilityHax(tabela = trigramTable, classe = i, frase = textTri);
      
      if(probTri > prob[2]){
        prob[2] = probTri;
        class[2] = i;
        
      }
      
      else{
        probBi = getProbabilityHax(tabela = bigramTable, classe = i, frase = textBi);
        
        if(probBi > prob[3]){
          prob[3] = probBi;
          class[3] = i;
        }
      }
    }
    
  }
  
  class[4] = sample(rownames(dictionary), size=1, prob = pesosDicionario);
  print(text)
  print(class)
  return (list(class,prob));
}

errorEvaluator=function(dictionary,bigram,trigram,quadgram,fourgramTestTable){
  
  total=0;
  correct=0;
  
  #answers = data.frame(colum)
  
  for(text in rownames(fourgramTestTable)){
    splited=unlist(strsplit(text," "))
    
    #print(paste(splited[1:4],collapse=" "))
    result=classifyHax(text=paste(splited[1:3],collapse=" "),dictionary=dictionary,
                    bigramTable=bigram,trigramTable=trigram,quadgramTable=quadgram)
    
    total=total + fourgramTestTable[text,1]
    
    if(splited[4] %in% result[[1]]){
      correct = correct + fourgramTestTable[text,1]
    }
    
    print("Resultado parcial:")
    print(paste("Corretas:",correct , "Total:" ,total , "%:",correct/total))
    
  }
  
  return (list(correct=correct,total=total,fraction=correct/total));
}

gramSimplifier = function(ngram, n){
  nrows=nrow(ngram)
  splited_words=strsplit(rownames(ngram)," ")
  
  #Pegamos as classes e setamos como names da nossa lista
  new_ngram=as.list(sapply(unique(unlist(splited_words)[1:nrows*n]),function(x) NULL))
  
  #print(names(new_ngram));
  
  #inicializamos todos os elementos
  new_ngram[]=list(list(total=0,contador=list()))
  
  for(text in splited_words){
    #Fazemos um join dos n-1 primeiro termos
    prefix=paste(text[1:(n-1)],collapse=" ")
    key=paste(text,collapse=" ")
    
    new_ngram[[text[n]]]$total=ngram[[key,1]]+new_ngram[[text[n]]]$total
    
    if(is.null(new_ngram[text[n]]$contador[prefix])){
      new_ngram[[text[n]]]$contador[[prefix]]=0
    }
    
    new_ngram[[text[n]]]$contador[[prefix]]=ngram[[key,1]]+new_ngram[[text[n]]]$contador[[prefix]]
    
  }
  
  return(new_ngram)
}

diminishStopwords = function(dictionary, stopwords){
  for(word in stopwords){
    
    if(word %in% rownames(dictionary)){
      dictionary[word, 1] = floor(dictionary[word, 1]/5);
    }
    
  }
  return(dictionary);
}